from typing import Type, Generic, TypeVar, Any, Optional,List
from sqlalchemy import Select, func, select
from sqlalchemy.ext.asyncio import AsyncSession
from pydantic import BaseModel,Field

T = TypeVar("T", bound=BaseModel)  # Pydantic响应模型
M = TypeVar("M")  # SQLAlchemy 模型

class Paginator(Generic[T, M]):
    """通用分页器"""

    def __init__(
        self,
        session: AsyncSession,
        model: Type[M],
        response_model: Type[T],
        base_query: Optional[Select] = None,
    ):
        self.session = session
        self.model = model
        self.response_model = response_model
        # self.base_query = base_query or select(self.model)
        self.base_query = base_query if base_query is not None else select(self.model)

    async def paginate(self, page: int = 1, page_size: int = 10) -> dict:
        """
        执行分页查询
        """
        # 验证分页参数
        page, page_size = self.validate_pagination(page, page_size)

        # 计算偏移量
        offset = (page - 1) * page_size

        # 执行数据查询
        data_query = self.base_query.offset(offset).limit(page_size)
        result = await self.session.execute(data_query)
        items = result.scalars().all()

        # 执行总数查询
        count_query = select(func.count()).select_from(self.base_query.subquery())
        total_result = await self.session.execute(count_query)
        total = total_result.scalar_one()

        # 转换为响应模型
        response_items = [self.response_model.model_validate(item)  for item in items]

        response_items_dict = [item.model_dump() for item in response_items]

        # 计算总页数
        total_pages = (total + page_size - 1) // page_size if total > 0 else 0

        return {
            "page": page,
            "page_size": page_size,
            "total_items": total,
            "total_pages": total_pages,
            "list": response_items_dict,
        }

    @staticmethod
    def validate_pagination(
        page: int, page_size: int, max_page_size: int = 100
    ) -> tuple[int, int]:
        """
        验证并标准化分页参数
        """
        if page < 1:
            page = 1

        if page_size < 1:
            page_size = 10
        elif page_size > max_page_size:
            page_size = max_page_size

        return page, page_size